const cheerio = require("cheerio");
const Services = require('ee-core/services');
const md5 = require('crypto-js/md5');
const Log = require('ee-core/log');
const fs = require('fs');
const { Utils } = require('ee-core');
const urlF = require('url')
const pathF = require("path");
const querystring = require('querystring');
const randomUserAgent = require("random-useragent");


// "./lib/api/attributes": {
//   "require": "./lib/api/attributes.js",
//   "import": "./lib/esm/api/attributes.js"
// }
const _ = require('lodash');

/**
 * example插件
 * @class
 */
class CollectAddon {

  auction = null
  auction = null
  uploadConfig = null
  collectConfig = null

  collectField = [
    'auction_title',
    'auction_address',
    'auction_date',
    'auction_paddress',
    'auction_pdate',
    'zc_list',
    'zc_title',
    'zc_thumb',
    'zc_date',
    'zc_address',
    'zc_url',
    'art_list',
    'art_total_page',
    'art_title',
    'art_url',
    'art_thumb',
    'art_listOrder',
    'art_author',
    'art_size',
    'art_date',
    'art_priceG',
    'art_priceRmb',
    'art_type',
    'art_content',
  ]
  // 自动注入 app 对象
  constructor(app) {
    this.app = app
  }

  async initCollectConfig(collect_id){
    const configs = await Services.get('auction').getCollectConfig()
    var collectConfig
    for(var i in configs){
      if(configs[i]['id'] == collect_id) {
        collectConfig = configs[i]
        break
      }
    }
    for(var i in this.collectField) {
      var f = this.collectField[i]
      if(!collectConfig.content.hasOwnProperty(f)) {
        collectConfig.content[f] = ''
        console.log('domain:' + this.collectConfig.domain + ', 缺少匹配规则：' + f)
      }
    }
    return collectConfig
  }

  async setRuleContent(data){
    const configs = await Services.get('auction').getCollectConfig()
    var collectConfig, index
    for(var i in configs){
      if(configs[i]['id'] == data.collect_id) {
        collectConfig = configs[i]
        index = i
        break
      }
    }
    collectConfig.content = data
    configs[index] = collectConfig
    await Services.get('auction').setCollectConfig(JSON.stringify(configs))
  }

  /**
   * hello
   *
   * @function 
   * @since 1.0.0
   */
  async auctionZc (auction) {
    const url = auction.url
    //雅昌特别判断
    if(auction.collect_id == 3) return await this.auctionYcZc(auction)

    const collectConfig = await this.initCollectConfig(auction.collect_id)
    const collectRules = collectConfig.content
    
    const $ = await this.getUrl(url);
    var dateText = $(collectRules.auction_date).text()
    var pdateText = $(collectRules.auction_pdate).text()
    const listItems = $(collectRules.zc_list);
    
    const parsedUrl = urlF.parse(url)
    const baseName = pathF.basename(url)
    const that = this
    var zcs = _.map(listItems, function (el, idx) {
      let _url = _.trim($(el).find(collectRules.zc_url).attr('href'))
      _url = that.getFullUrl(_url, parsedUrl, baseName)
      
      return {
        url: _url,
        thumb: _.trim($(el).find(collectRules.zc_thumb).attr('src')),
        title: _.trim($(el).find(collectRules.zc_title).text()),
        date: _.trim($(el).find(collectRules.zc_date).text().replace('拍卖时间：', '').replace('拍卖时间:', '')),
        address: _.trim($(el).find(collectRules.zc_address).text().replace('拍卖地点：', '').replace('拍卖地点:', '')),
      }
    });
    var auction = {
      title: _.trim($(collectRules.auction_title).text()),
      date: JSON.stringify(this.getStartEndDate(_.trim(dateText))),
      address: _.trim($(collectRules.auction_address).text()).replace('拍卖地点：', '').replace('拍卖地点:', ''),
      pdate: JSON.stringify(this.getPStartEndDate(_.trim(pdateText))),
      paddress: _.trim($(collectRules.auction_paddress).text()).replace('预展地点：', '').replace('预展地点:', ''),
      zcList: zcs
    }
    // console.log(auction)
    return auction;
  }

  async auctionYcZc(auction){
    //获取拍卖id
    const code = await this.getYachangAuctionCode(auction.url)
    const data = await this.postUrl('https://api.artron.net/v1/session/detail', {sessionCode: code})
    if(data.code != 0) {
      console.log('auction error:' + code + ',' + data.message)
      return false
    }
    
    var zcs = []
    for(var i in data.data.specialsList){
      const item = data.data.specialsList[i]
      var thumb = this.getThumbUrlYC(item.coverPic)
      var res = await this.uploadFile(thumb)
      if(res.code == 1) {
        thumb = res.url
      }else{
        console.log('专场图片上传失败：id:' + thumb)
      }
      var zcaddress = _.find(item.extraInfo, { 'picUrl': 'listicon_address' })
      var zcdate = _.find(item.extraInfo, { 'picUrl': 'listicon_date' })
      zcs.push({
        url: 'https://api.artron.net/v1/special/auctions/list?specialCode=' + item.specialCode,
        id: item.specialCode,
        thumb: thumb,
        title: item.name,
        date: zcdate?zcdate.text:'',
        address: zcaddress?zcaddress.text:'',
      })
    }
    // console.log(data.data.detailExtraInfo)
    var paddress = _.find(data.data.detailExtraInfo, { 'label': '预展地点' })
    var address =  _.find(data.data.detailExtraInfo, { 'label': '拍卖地点' })
    var company =  _.find(data.data.detailExtraInfo, { 'label': '拍卖公司' })
    var auction = {
      title: data.data.name + '-' + _.find(data.data.detailExtraInfo, { 'label': '拍卖公司' }).text + '---' + (company?company.text:''),
      id: data.data.sessionCode,
      date: JSON.stringify(this.getStartEndDateYC(_.find(data.data.detailExtraInfo, { 'label': '拍卖时间' }).text)),
      pdate: JSON.stringify(this.getPStartEndDateYC(_.find(data.data.detailExtraInfo, { 'label': '预展时间' }).text)),
      address: address?address.text:'',
      paddress: paddress?paddress.text:'',
      zcList: zcs
    }
    return auction
  }


  async setAuction(auction){
    this.auction = auction
    return this
  }


  async collectZc(auction, zc, page = 1){
    //雅昌特别判断
    if(auction.collect_id == 3) return await this.collectYcZc(auction, zc, page = 1)

    const collectConfig = await this.initCollectConfig(auction.collect_id)
    const collectRules = collectConfig.content
    this.auction = auction

    const $ = await this.getUrl(zc.url + (zc.url.indexOf('?')>=0?'&':'?') + 'page=' + page)
    if(page == 1) {
      zc['listArts'] = []
    }
    const listItems = $(collectRules.art_list)
    console.log(zc.url + (zc.url.indexOf('?')>=0?'&':'?') + 'page=' + page)
    var totalPage = $(collectRules.art_total_page).text().match(/[0-9]/g)
    if(totalPage && totalPage.length>0)totalPage = totalPage.join('')
    //当采集不到分页总数的时候，默认100页
    if(totalPage == '' || !totalPage) totalPage = 100
    
    if(listItems.length == 0)totalPage = page

    const parsedUrl = urlF.parse(zc.url)
    const baseName = pathF.basename(zc.url)
    
    for(var i in listItems) {
      var el = listItems[i]
      if(typeof el != 'object')break
      var url = _.trim($(el).find(collectRules.art_url).attr('href'))
      url = this.getFullUrl(url, parsedUrl, baseName)
      var art =  {
        url,
        zc_id: zc.id,
        auction_id: zc.auction_id,
        thumb: _.trim($(el).find(collectRules.art_thumb).attr('src')),
        title: _.trim($(el).find(collectRules.art_title).text()),
        listOrder: '',
        priceG: '',
        author: '',
        size: '',
        priceRmb: '',
        type: '',
        date: '',
        content: '',
        status: 0,
        id: md5(url).toString()
      }
      art = await this.collectArt(art, collectRules)
      // return art
      //插入数据库, 调试的时候 直接返回1个即可
      if(auction.id != 0) {
        Services.get('art').add(art)
      }else{
        return art
      }
      // zc['listArts'].push(art)
    }
    
    if((page + 1)<=totalPage && auction.id != 0)await this.collectZc(auction, zc, page+1)
    //最后一页 请求更新专场状态
    if(page == totalPage && auction.id != 0) {
      var countArts = await Services.get('art').count('zc_id', zc.id)
      Services.get('zc').update({id: zc.id, status: 2, countArts})
    }
    return zc
  }
  async collectArt(art, collectRules){
    const $ = await this.getUrl(art.url)
    var art_thumb = _.trim($(collectRules.art_thumb).attr('src'))
    var art_title = _.trim($(collectRules.art_title).text())
    art.thumb = art_thumb?art_thumb:art.thumb
    art.title = art_title?art_title:art.title
    art.listOrder = _.trim($(collectRules.art_listOrder).text())
    art.author = _.trim($(collectRules.art_author).text())
    art.size = _.trim($(collectRules.art_size).text())
    art.date = _.trim($(collectRules.art_date).text())
    art.priceG = _.trim($(collectRules.art_priceG).text())
    art.priceRmb = _.trim($(collectRules.art_priceRmb).text())
    art.type = _.trim($(collectRules.art_type).text())
    art.content = _.trim($(collectRules.art_content).text())
    const res = await this.uploadFile(art.thumb)
    if(res.code == 1) {
      art.thumb = res.url
    }else{
      console.log('艺术品图片上传失败：id:' + art.id)
    }
    return art
  }


  async collectYcZc(auction, zc){
    const data = await this.postUrl(zc.url, {limit: 10000})
    if(data.code != 0) {
      console.log('auction error:' + auction.url + ',' + data.message)
      return false
    }
    for(var i in data.data.list) {
      const item = data.data.list[i]
      var url = 'https://auction.artron.net/paimai-' + item.ArtCode
      var id = md5(url).toString()
      var art =  {
        url,
        zc_id: zc.id,
        auction_id: auction.id,
        thumb: this.getThumbUrlYC(item.FileName),
        title: item.Title,
        listOrder: item.TlNumber,
        priceG: '',
        author: '',
        size: '',
        priceRmb: item.CurrencyPrice,
        type: '',
        date: item.Date,
        content: '',
        status: 0,
        id: md5(url).toString()
      }
      
      var res = await this.uploadFile(art.thumb)
      if(res.code == 1) {
        art.thumb = res.url
      }else{
        console.log('艺术品图片上传失败：id:' + art.id)
      }
      art = await this.collectArtYC(art)
      Services.get('art').add(art)
      // console.log(art)
      // break
    }
    var countArts = await Services.get('art').count('zc_id', zc.id)
    Services.get('zc').update({id: zc.id, status: 2, countArts})
    return zc
  }

  async collectArtYC(art){
    const $ = (await this.getUrl(art.url))
    const str = $('script').eq(0).html().replace('window.__INITIAL_STATE__=', '').replace(';(function(){var s;(s=document.currentScript||document.scripts[document.scripts.length-1]).parentNode.removeChild(s);}());', '')
    var data
    try{
      data = JSON.parse(str)
    }catch(e){
      data = {}
      console.log('YaChang JSON ERROR:' + art.url)
      return art
    }

    var content = _.find(data.pageProDetail.data.detail.extraInfo, {label: '拍品描述'})
    var priceG = _.find(data.pageProDetail.data.detail.extraInfo, {label: '估价'})
    var author = _.find(data.pageProDetail.data.detail.extraInfo, {label: '作者'})
    var type = _.find(data.pageProDetail.data.detail.extraInfo, {label: '材质'})
    var size = _.find(data.pageProDetail.data.detail.extraInfo, {label: '尺寸'})


    if(content)art.content = content.fullText
    if(priceG)art.content = priceG.fullText
    if(author)art.content = author.fullText
    if(type)art.content = type.fullText
    if(size)art.content = size.fullText
    return art
  }


  async getUrl(url){
    const options = {
      method: 'GET',
      timeout: 15000, 
      headers: {
        'content-type': 'text/html',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
        'Referer': url,
        'Sec-Ch-Ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"'
      }, 
      dataType: 'text'
    };
    
    if(this.auction && this.auction.url && this.auction.url.indexOf('https')>=0) {
      url = url.replace('http://', 'https://')
    }
    const result = await this.app.curl(url, options)
    return cheerio.load(result.data)
  }
  async postUrl(url, data){
    const userAgent = randomUserAgent.getRandom()
    const options = {
      method: 'POST',
      timeout: 15000, 
      headers: {
        'content-type': 'application/x-www-form-urlencoded',
        'User-Agent': userAgent,
        'Referer': url,
        'Origin': 'https://auction.artron.net',
        'Referer': 'https://auction.artron.net/'
      },
      dataType: 'json',
      data
    }
    var result
    try{
      result = await this.app.curl(url, options)
    }catch(e){
      // console.log(e)
    }
    return result?(result.data):false
  }

  async postArtsCollect(){
    const list = await Services.get('art').list({}, 30)
    Log.info('艺术品:' + list.length)
    for(var i in list){
      // if(i < 3)continue
      var art = list[i]
      Log.info('art:' + art.id + ',list')
      var auction = await Services.get('auction').show(art.auction_id)
      var zc = await Services.get('zc').show(art.zc_id)
      
      if(!auction || !zc) {
        await Services.get('art').update({id: art.id, status: 1, remark: '拍卖或者专场被删除'})
        Log.info('art:' + art.id + ',拍卖或者专场被删除')
        continue
      }
      //如果图片没有上传，则上传图片后再发生数据
      if((typeof art.thumb == 'string' && art.thumb.indexOf('auction.pics')<0)) {
        const rethumb = await this.uploadFile(art.thumb)
        if(rethumb.code == 0) {
          await Services.get('art').update({id: art.id, remark: '艺术品图片上传失败'})
          Log.info('art:' + art.id + ',艺术品图片上传失败')
          continue
        }else{
          art.thumb = rethumb
        }
        await Services.get('art').update({id: art.id, thumb: art.thumb})
      }
      var token = await Services.get('auction').getToken()
      // console.log(auction)
      delete auction['zcList']
      delete zc['arts']
      // console.log({auction, zc, art, token})
      const result = await this.postServer({auction, zc, art, token})
      console.log(result)
      if(result.data.code == 1) {
        Services.get('art').delete({id: art.id})
        Services.get('auction').update(art.auction_id, {remark: '成功'})
        // Services.get('art').update({id: art.id, status: 1, remark: JSON.stringify(result.data)})
        Log.info('art:' + art.id + ',OK')
      }else{
        Services.get('auction').update(art.auction_id, {remark: '失败'})
        Log.info('art:' + art.id + ',error')
      }
      
    }
  }
  async postServer(data){
    const options = {
      method: 'POST',
      timeout: 15000, 
      headers: {
        'Authorization': 'Bearer ' + data.token,
        'content-type': 'application/json',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
        'Sec-Ch-Ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"'
      }, 
      dataType: 'json',
      data
    };
    var url = 'http://work.manage.zhuokearts.com/api/collect/art'
    const result = await this.app.curl(url, options)
    return result.data

  }

  //上传图片
  //获取上传的时候参数
  async getUploadConfig(){
    if(this.uploadConfig)return;
    var token = await Services.get('auction').getToken()
    if(!token) {
      console.log('图片上传参数错误')
      return false
    }
    const options = {
      method: 'POST',
      timeout: 15000, 
      headers: {
        'Authorization': 'Bearer ' + token,
        'content-type': 'application/json',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
        'Sec-Ch-Ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"'
      }, 
      dataType: 'json'
    };
    var url = 'http://work.manage.zhuokearts.com/api/getUploadConfig'
    const result = await this.app.curl(url, options)
    this.uploadConfig = result.data.data
    
    return true

  }

  async uploadFile(url){
    if(!url || url == '')return false

    await this.getUploadConfig()
    url = this.removeThumbUrlQueryString(url)
    var fileExtension = '.jpg'
    if(url.indexOf('.')>=0) {
      fileExtension = url.match(/\.[^.]+$/)[0];
    }
    const name = md5(url).toString() + fileExtension
    const uploadConfig = this.uploadConfig
    const pathName = 'auction.pics/' + uploadConfig.file + '/' + name
    const fileName = await this.readFileContent(url, name)
    // console.log(imageBuffer)
    const data = {
      'key': pathName,
      'policy': uploadConfig.policy,
      'OSSAccessKeyId': uploadConfig.accessKeyId,
      'success_action_status': '200', //让服务端返回200，不然，默认会返回204
      'signature': uploadConfig.signature,
      'x-oss-security-token': uploadConfig.security_token
    }
    const options = {
      method: 'POST',
      timeout: 15000, 
      headers: {
        'content-type': 'multipart/form-data',
      },
      files: {
        file: Buffer.from(fileName)
      },
      data
    };
    var url = 'https://3img-zhuokearts.oss-cn-beijing.aliyuncs.com'
    const result = await this.app.curl(url, options)
    if(result.status == 200) {
      return {code: 1, url: pathName}
    }else{
      this.getCollectConfig()
      return {code: 0, url: '上传图片失败'}
    }
  }

  async readFileContent(url, name){
    const path = Utils.getStorageDir() + '/tmp/'+ name
    if(fs.existsSync(path)) return path
    const options = {
      method: 'GET',
      timeout: 15000, 
      headers: {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
        'Sec-Ch-Ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"'
      }
    };
    const result = await this.app.curl(url, options)
    return result.data
  }

  async getCollectConfig(){
    const options = {
      method: 'POST',
      timeout: 15000, 
      headers: {
        'content-type': 'application/json',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
        'Sec-Ch-Ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"'
      }, 
      dataType: 'json'
    };
    var url = 'http://work.manage.zhuokearts.com/api/index'
    const result = await this.app.curl(url, options)
    await Services.get('auction').setCollectConfig(JSON.stringify(result.data.data.collect))
    this.collectConfig = result.data.data.collect
    // console.log(this.collectConfig)
    return true
  }

  async getYachangAuctionCode(url){
    const arr = _.trim(url, '/').split('/')
    return _.last(arr)
  }

  getStartEndDateYC(dateText){
    const arr = dateText.split('~')
    return {start: _.trim(arr[0]), end:  _.trim(arr[1])}
  }
  getPStartEndDateYC(dateText){
    var arr = dateText.split(' ')
    return this.getPStartEndDate(arr[0])
  }
  getThumbUrlYC(url){
    //获取src=的图片地址
    if(url.indexOf('src=')>=0) {
      const parsedUrl = querystring.parse(url)
      url = parsedUrl.src
    }
    return url
  }
  

  getStartEndDate(dateText){
    dateText = dateText.replace('拍卖时间：', '').replace('拍卖时间:', '')
    const arr = _.split(dateText, '-', 2)
    // console.log(arr)
    if(arr.length != 2)return {start: '', end: ''}
    var start = _.trim(arr[0])
    if(isNaN(Number(start.slice(-1)))) start = start.slice(0, start.length-1)
    var end = _.trim(arr[1])
    if(isNaN(Number(end.slice(-1)))) end = end.slice(0, end.length-1)
    const n = end.length
    if(n<=2) {
      var ends = this.getStartDateYearMonth(start)
    }else{
      var ends = start.substring(0, start.length-n)
      //防止位数不一致导致数字错误
      if(!isNaN(Number(ends.slice(-1))))ends = ends.slice(0, ends.length-1)
      if(!isNaN(Number(ends.slice(-1))))ends = ends.slice(0, ends.length-1)
    }
    return {start, end: ends + end}
  }
  getStartDateYearMonth(s){
    if(!isNaN(Number(s.slice(-2)))) {
      return s.substring(0, s.length-2)
    }else{
      return s.substring(0, s.length-1)
    }
  }
  getPStartEndDate(dateText){
    dateText = dateText.replace('预展时间：', '').replace('预展时间:', '')
    if(dateText.indexOf('-')) {
      return this.getStartEndDate(dateText)
    }
    const date = dateText.substring(0,  10)
    return {start: _.trim(date), end: _.trim(date)}
  }
  getFullUrl(_url, parsedUrl, baseName){
    if(_url.indexOf('http')<0) {
      if(_url.startsWith('/'))  {
        _url = parsedUrl.protocol + '//' + parsedUrl.host + _url
      }else{
        _url = url.replace(baseName, _url)
      }
    }
    return _url
  }
  removeThumbUrlQueryString(url){
    url = url.toLowerCase()
    //去除url后面的参数
    if(url.indexOf('jpg?')>=0 || url.indexOf('png?')>=0 || url.indexOf('jpeg?')>=0) {
      url = url.replace(/\?.*$/, "")
    }
    return url
  }

}

CollectAddon.toString = () => '[class CollectAddon]';
module.exports = CollectAddon;